package com.demo.config;

import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
import com.demo.filter.ReqContextFilter;
import com.demo.interceptor.ApiKeyAccessInterceptor;
import com.demo.interceptor.LogInterceptor;
import org.apache.commons.lang3.StringUtils;
import org.passay.MessageResolver;
import org.passay.spring.SpringMessageResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

/**
 * @author wangfengchen
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

  @Autowired
  private I18nHelper i18nHelper;
  @Autowired
  private MessageSource messageSource;


  /**
   * 注册自定义过滤器
   *
   * @return
   */
  @Bean
  public FilterRegistrationBean<ReqContextFilter> requestContextFilterRegistration() {
    FilterRegistrationBean<ReqContextFilter> bean = new FilterRegistrationBean<>();
    ReqContextFilter reqContextFilter = new ReqContextFilter(i18nHelper);
    // 注意必须是 /** 或者 /*/xxx，/* 结尾不生效
    reqContextFilter.setExcludes(Collections.singletonList("/actuator/**"));
    bean.setFilter(reqContextFilter);
    // 过滤器名称
    bean.setName("RequestContextFilter");
    // 过滤所有路径
    bean.addUrlPatterns("/*");
    // 优先级，越低越优先，注意：通过FilterRegistrationBean实例设置优先级可以生效，通过@WebFilter和@Order(1)注解无效
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
  }

  /**
   * 添加拦截器
   *
   * @param registry
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
//    registry.addInterceptor(localeChangeInterceptor());
    registry.addInterceptor(new LogInterceptor()).excludePathPatterns("/error");
    registry.addInterceptor(new ApiKeyAccessInterceptor()).excludePathPatterns("/error");
  }

  /**
   * 自定义消息转换器
   *
   * @param converters
   */
  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.clear();
    // 自定义使用FastJsonHttpMessageConverter
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    // https://github.com/alibaba/fastjson2/wiki/Features_cn
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
    fastJsonConfig.setReaderFeatures(
        JSONReader.Feature.FieldBased,
        JSONReader.Feature.SupportArrayToBean);
    fastJsonConfig.setWriterFeatures(
        JSONWriter.Feature.PrettyFormat,
        JSONWriter.Feature.BrowserCompatible,
        JSONWriter.Feature.WriteNulls,
        JSONWriter.Feature.WriteMapNullValue,
        JSONWriter.Feature.WriteLongAsString
    );
    fastJsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
    fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
    // 防止spring boot admin报错(No converter for [class org.springframework.boot.actuate.health.SystemHealth] with preset Content-Type 'null')
    List<MediaType> list = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.ALL);
    fastJsonHttpMessageConverter.setSupportedMediaTypes(list);
    // 在ResponseBody注解下，Spring处理返回值为String时会用到StringHttpMessageConverter，我们只需要在配置文件中设置好他的编译编码就ok了
    // 保证StringHttpMessageConverter在FastJsonHttpMessageConverter前被调用
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
    stringHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
    converters.add(stringHttpMessageConverter);
    // FastJsonHttpMessageConverter 优先级涉及转义问题
    converters.add(fastJsonHttpMessageConverter);
  }

  /**
   * 配置 Passay 使用 Spring 的 MessageSource 实现国际化
   *
   * @return MessageResolver
   */
  @Bean
  public MessageResolver messageResolver() {
    return new SpringMessageResolver(messageSource);
  }

  /**
   * 国际化默认解析器，默认设置为中文，这种方法解决了比如先选择英语之后再切回默认的时候依然还是英语的问题，如果没有lang则默认用中文
   */
  @Bean
  public LocaleResolver localeResolver() {
    return new LocaleResolver() {
      @Override
      public Locale resolveLocale(HttpServletRequest request) {
        // 获取请求中参数
//        String lang = request.getParameter("lang");
        String lang = request.getHeader("Accept-Language");
        // 获取默认的区域信息解析器
        Locale locale = Locale.SIMPLIFIED_CHINESE;
        // 根据请求中的参数重新构造区域信息对象
        if (StringUtils.isNotBlank(lang)) {
          // 同时支持中英文中划线和下划线
          String[] s = StringUtils.split(lang, "-_—");
          if (s.length == 2) {
            locale = new Locale(StringUtils.lowerCase(s[0]), StringUtils.upperCase(s[1]));
          } else if (StringUtils.contains(lang, Locale.ENGLISH.getLanguage())) {
            // 兼容传错的情况: en 默认为us
            locale = Locale.US;
          }
        }
        return locale;
      }

      @Override
      public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

      }
    };
  }


}
